using System;
using System.Collections.Generic;
using System.Text;
using OpenALDotNet;
using SlimDX;
using Barrage.Elements;

namespace Barrage.Audios
{
    /// <summary>
    /// Implements 3D Positioned audio sources, using the Parent Item Motion as the position of the source
    /// </summary>
    public class SpatializedAudio : Audio
    {
        AudioSource source;
        bool playing = false;

        Camera camera = null;
        /// <summary>
        /// Associated audio camera to perform sound spatialization
        /// </summary>
        public Camera Camera { get { return camera; } set { camera = value; } }
        Vector3 velocity;
        /// <summary>
        /// Sound velocity
        /// </summary>
        public Vector3 Velocity{get{return velocity;}set{velocity=value;}}
        
        /// <summary>
        /// Constructor. Gets the buffer from the audio file and inits default data
        /// </summary>
        /// <param name="file">Audio file</param>
        public SpatializedAudio(AudioFile file)
        {
            source = new AudioSource();
            source.EnqueueBuffer(file.Buffer);
            // Spatialized sound
            source.IsRelative = true;
            // Do not loop by default
            source.IsLooping = false;
        }

        /// <summary>
        /// Constructor. Gets the buffer from the audio file and inits default data
        /// </summary>
        /// <param name="file">Audio file</param>
        /// <param name="camera">Camera used to spatialize the sound</param>
        public SpatializedAudio(AudioFile file, Camera camera)
            : this(file)
        {
            this.camera = camera;
        }

        /// <summary>
        /// \internal Updates audio position
        /// </summary>
        /// <param name="item">Item rendering the sound</param>
        public override void Update(Item item){
            if (playing)
            {
                Matrix inverseTransform;
                if (camera!=null) 
                    inverseTransform = camera.Motion;
                else
                {
                    if (Scene.CurrentInstance.Camera==null) return;
                    inverseTransform = Scene.CurrentInstance.Camera.Motion;
                }

                Vector4 tv=Vector3.Transform(item.Motion.WorldTranslation,inverseTransform);
                // The default OpenAL listener hears to 0,0,-1
                source.Position = new Vector3(tv.X,tv.Y,-tv.Z);
                /*tv =Vector3.Transform(Velocity,inverseTransform);
                    source.Velocity = new Vector3(tv.X, tv.Y, tv.Z);*/                
            }
        }

        /// <summary>
        /// Distance at which the volume should drop by half
        /// </summary>
        public float ReferenceDistance { get { return source.ReferenceDistance; } set { source.ReferenceDistance = value; } }

        /// <summary>
        /// \internal Gets / Sets if the audio should loop or not
        /// </summary>
        public override bool Loop
        {
            get
            {
                return source.IsLooping;
            }
            set
            {
                source.IsLooping = value;
            }
        }

        /// <summary>
        /// \internal Play speed of the sound (1 is normal speed)
        /// </summary>
        public override float Speed
        {
            get
            {
                return source.Pitch;
            }
            set
            {
                source.Pitch = value;
            }
        }

        /// <summary>
        /// \internal Starts sound
        /// </summary>

        public override void Start()
        {
            source.Play();
            playing = true;
        }

        /// <summary>
        /// \internal Stops the sound
        /// </summary>
        public override void Stop()
        {
            source.Stop();
            playing = false;
        }

        /// <summary>
        /// \internal Returns true if the sound is being played
        /// </summary>
        public override bool Playing
        {
            get { return playing; }
        }

        /// <summary>
        /// \internal Sound volume (1 is default)
        /// </summary>
        public override float Volume
        {
            get
            {
                return source.Gain;
            }
            set
            {
                source.Gain = value;
            }
        }
    }
}
